home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / sbin / adduser < prev    next >
Text File  |  2008-06-26  |  34KB  |  1,053 lines

  1. #!/usr/bin/perl
  2.  
  3. # adduser: a utility to add users to the system
  4. # addgroup: a utility to add groups to the system
  5. my $version = "3.108ubuntu1";
  6.  
  7. # Copyright (C) 1997, 1998, 1999 Guy Maor <maor@debian.org>
  8. # Copyright (C) 1995 Ted Hajek <tedhajek@boombox.micro.umn.edu>
  9. #                     Ian A. Murdock <imurdock@gnu.ai.mit.edu>
  10. # Bugfixes and other improvements Roland Bauerschmidt <rb@debian.org>
  11. # General scheme of the program adapted by the original debian 'adduser'
  12. #  program by Ian A. Murdock <imurdock@gnu.ai.mit.edu>.
  13. #
  14. #    This program is free software; you can redistribute it and/or modify
  15. #    it under the terms of the GNU General Public License as published by
  16. #    the Free Software Foundation; either version 2 of the License, or
  17. #    (at your option) any later version.
  18. #
  19. #    This program is distributed in the hope that it will be useful,
  20. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22. #    GNU General Public License for more details.
  23. #
  24. #    You should have received a copy of the GNU General Public License
  25. #    along with this program; if not, write to the Free Software
  26. #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  27. #
  28. #
  29. ####################
  30. # See the usage subroutine for explanation about how the program can be called
  31. ####################
  32.  
  33. use warnings;
  34. use strict;
  35. use Debian::AdduserCommon;
  36. use Getopt::Long;
  37.  
  38. BEGIN {
  39.     local $ENV{PERL_DL_NONLAZY}=1;
  40.     eval 'use Locale::gettext';
  41.     if ($@) {
  42.     *gettext = sub { shift };
  43.     *textdomain = sub { "" };
  44.     *LC_MESSAGES = sub { 5 };
  45.     }
  46.     eval {
  47.     require POSIX;
  48.     import POSIX qw(setlocale);
  49.     };
  50.     if ($@) {
  51.     *setlocale = sub { return 1 };
  52.     }
  53.     eval {
  54.     require I18N::Langinfo;
  55.     import I18N::Langinfo qw(langinfo YESEXPR NOEXPR);
  56.     };
  57.     if ($@) {
  58.     *langinfo = sub { return shift; };
  59.     *YESEXPR  = sub { "^[yY]" };
  60.     *NOEXPR   = sub { "^[nN]" };
  61.     }
  62. }
  63.  
  64. setlocale(LC_MESSAGES, "");
  65. textdomain("adduser");
  66. my $yesexpr = langinfo(YESEXPR());
  67.  
  68. my %config;            # configuration hash
  69.  
  70. my @defaults = ("/etc/adduser.conf");
  71. my $nogroup_id = getgrnam("nogroup") || 65534;
  72. $0 =~ s+.*/++; 
  73.  
  74. our $verbose = 1;        # should we be verbose?
  75. my $allow_badname = 0;        # should we allow bad names?
  76. my $ask_passwd = 1;        # ask for a passwd? 
  77. my $disabled_login = 0;        # leave the new account disabled?
  78.  
  79. our $configfile = undef;
  80. our $found_group_opt = undef;
  81. our $found_sys_opt = undef;
  82. our $ingroup_name = undef;
  83. our $new_firstuid = undef;
  84. our $new_gecos = undef;
  85. our $new_gid = undef;
  86. our $new_lastuid = undef;
  87. our $new_uid = undef;
  88. our $no_create_home = undef;
  89. our $special_home = undef;
  90. our $special_shell = undef;
  91. our $add_extra_groups = 0;
  92.  
  93. # Global variables we need later
  94. my $existing_user = undef;
  95. my $existing_group = undef;
  96. my $new_name = undef;
  97. my $make_group_also = 0;
  98. my $home_dir = undef;
  99. my $undohome = undef;
  100. my $undouser = undef;
  101. my $undogroup = undef;
  102. my $shell = undef;
  103. my $first_uid = undef;
  104. my $last_uid = undef;
  105. my $dir_mode = undef;
  106. my $perm = undef;
  107.  
  108. our @names;
  109.  
  110. # Parse options, sanity checks
  111. unless ( GetOptions ("quiet|q" => sub { $verbose = 0 },
  112.             "force-badname" => \$allow_badname,
  113.         "help|h" => sub { &usage(); exit 0 },
  114.         "version|v" => sub { &version(); exit 0 },
  115.         "system" => \$found_sys_opt,
  116.         "group" => \$found_group_opt,
  117.         "ingroup=s" => \$ingroup_name,
  118.         "home=s" => \$special_home,
  119.         "gecos=s" => \$new_gecos,
  120.         "shell=s" => \$special_shell,
  121.         "disabled-password" => sub { $ask_passwd = 0 },
  122.         "disabled-login" => sub { $disabled_login = 1; $ask_passwd = 0 },
  123.         "uid=i" => \$new_uid,
  124.         "firstuid=i" => \$new_firstuid,
  125.         "lastuid=i" => \$new_lastuid,
  126.         "gid=i" => \$new_gid,
  127.         "conf=s" => \$configfile,
  128.         "no-create-home" => \$no_create_home,
  129.             "add_extra_groups" => \$add_extra_groups,
  130.         "debug" => sub { $verbose = 2 } ) ) {
  131.     &usage();
  132.     exit 1;
  133. }
  134.  
  135. # everyone can issue "--help" and "--version", but only root can go on
  136. dief (gtx("Only root may add a user or group to the system.\n")) if ($> != 0);
  137.  
  138. if( defined($configfile) ) { @defaults = ($configfile); }
  139.  
  140. # detect the right mode
  141. my $action = $0 eq "addgroup" ? "addgroup" : "adduser";
  142. if (defined($found_sys_opt)) {
  143.   $action = "addsysuser" if ($action eq "adduser");
  144.   $action = "addsysgroup" if ($action eq "addgroup");
  145. }
  146.  
  147. # explicitly set PATH, because super (1) cleans up the path and makes adduser unusable;
  148. # this is also a good idea for sudo (which doesn't clean up)
  149. $ENV{"PATH"}="/bin:/usr/bin:/sbin:/usr/sbin";
  150. $ENV{"IFS"}=" \t\n";
  151.  
  152. ############################
  153. # checks related to @names #
  154. ############################
  155.  
  156.  
  157. while (defined(my $arg = shift(@ARGV))) {
  158.   push (@names, $arg);
  159. }
  160.  
  161. if ( (! defined $names[0]) || length($names[0]) == 0 || @names > 2) {
  162.     dief (gtx("Only one or two names allowed.\n"));
  163. }
  164.         
  165.  
  166. if (@names == 2) {    # must be addusertogroup
  167.     dief (gtx("Specify only one name in this mode.\n"))
  168.     if ($action eq "addsysuser" || $found_group_opt);
  169.     $action = "addusertogroup";
  170.     $existing_user = shift (@names);
  171.     $existing_group = shift (@names);
  172. }
  173. else { # 1 parameter, must be adduser
  174.     $new_name = shift (@names);
  175. }
  176.  
  177. ###################################
  178. # check for consistent parameters #
  179. ###################################
  180.  
  181. if ($action ne "addgroup" &&
  182.     defined($found_group_opt) +defined($ingroup_name) +defined($new_gid) > 1 ) {
  183.     dief (gtx("The --group, --ingroup, and --gid options are mutually exclusive.\n"));
  184. }
  185.  
  186.  
  187. if ((defined($special_home)) && ($special_home !~ m+^/+ )) {
  188.   dief (gtx("The home dir must be an absolute path.\n"));
  189. }
  190.        
  191. if (defined($special_home) && $verbose) {
  192.     printf gtx("Warning: The home dir %s you specified already exists.\n"),$special_home
  193.       if (!defined($no_create_home) && -d $special_home);
  194.     printf gtx("Warning: The home dir %s you specified can't be accessed: %s\n"), $special_home, $!
  195.       if (defined($no_create_home) && ! -d $special_home);
  196. }
  197.  
  198.  
  199. if ($found_group_opt) {
  200.     if ($action eq "addsysuser") {
  201.     $make_group_also = 1;
  202.     }
  203.     elsif ($found_sys_opt) {
  204.     $action = "addsysgroup";
  205.     }
  206.     else {
  207.     $action = "addgroup";
  208.     }
  209. }
  210.  
  211.  
  212. $ENV{"VERBOSE"} = $verbose;
  213. $ENV{"DEBUG"}   = $verbose;
  214.  
  215.  
  216. # preseed configuration data and then read the config file
  217. preseed_config(\@defaults,\%config);
  218.  
  219. &checkname($new_name, $found_sys_opt) if defined $new_name;
  220. $SIG{'INT'} = $SIG{'QUIT'} = $SIG{'HUP'} = 'handler';
  221.  
  222. #####
  223. # OK, we've processed the arguments.  $action equals one of the following,
  224. # and the appropriate variables have been set:
  225. #
  226. # $action = "adduser"
  227. #    $new_name                - the name of the new user.
  228. #    $ingroup_name | $new_gid - the group to add the user to
  229. #    $special_home, $new_uid, $new_gecos - optional overrides
  230. # $action = "addgroup"
  231. #    $new_name                - the name of the new group
  232. #    $new_gid                 - optional override
  233. # $action = "addsysgroup"
  234. #    $new_name                - the name of the new group
  235. #    $new_gid                 - optional override
  236. # $action = "addsysuser"
  237. #    $new_name                - the name of the new user
  238. #    $make_group_also | $ingroup_name | $new_gid | 0  - which group
  239. #    $special_home, $new_uid, $new_gecos - optional overrides
  240. # $action = "addusertogroup"
  241. #    $existing_user           - the user to be added
  242. #    $existing_group          - the group to add her to
  243. #####
  244.  
  245.  
  246. #################
  247. ## addsysgroup ##
  248. #################
  249. if ($action eq "addsysgroup") {
  250.  
  251.     # Check if requested group already exists and we can exit safely
  252.     my $ret = existing_group_ok($new_name, $new_gid);
  253.  
  254.     if ($ret == 3) {
  255.         print STDERR "$0: " if $verbose;
  256.     printf STDERR (gtx("The group `%s' already exists as a system group. Exiting.\n"), $new_name) if $verbose;
  257.     exit 0;
  258.     }
  259.  
  260.     if ($ret == 1) {
  261.         print STDERR "$0: " if $verbose;
  262.     printf STDERR (gtx("The group `%s' already exists and is not a system group. Exiting.\n"), $new_name) if $verbose;
  263.     exit 1;
  264.     }
  265.  
  266.     if ($ret == 2) {
  267.         print STDERR "$0: " if $verbose;
  268.     printf STDERR (gtx("The group `%s' already exists, but has a different GID. Exiting.\n"), $new_name) if $verbose;
  269.     exit 1;
  270.     }
  271.  
  272.     dief (gtx("The GID `%s' is already in use.\n"),$new_gid)
  273.     if (defined($new_gid) && defined(getgrgid($new_gid)));
  274.  
  275.     if (!defined($new_gid)) {
  276.         $new_gid = &first_avail_gid($config{"first_system_gid"},
  277.                    $config{"last_system_gid"});
  278.         if ($new_gid == -1) {
  279.         print STDERR "$0: ";
  280.         printf STDERR gtx("No GID is available in the range %d-%d (FIRST_SYS_GID - LAST_SYS_GID).\n"),$config{"first_system_gid"},$config{"last_system_gid"};
  281.             dief (gtx("The group `%s' was not created.\n"),$new_name);
  282.         }
  283.     }
  284.  
  285.  
  286.     printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
  287.     &invalidate_nscd("group");
  288.     my $groupadd = &which('groupadd');
  289.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  290.     &invalidate_nscd("group");
  291.     print (gtx("Done.\n")) if $verbose;
  292.     exit 0;
  293. }
  294.  
  295.  
  296. ##############
  297. ## addgroup ##
  298. ##############
  299. if ($action eq "addgroup") {
  300.     dief (gtx("The group `%s' already exists.\n"),$new_name)
  301.     if (defined getgrnam($new_name));
  302.     dief (gtx("The GID `%s' is already in use.\n"),$new_gid)
  303.     if (defined($new_gid) && defined(getgrgid($new_gid)));
  304.     if (!defined($new_gid)) {
  305.         $new_gid = &first_avail_gid($config{"first_gid"},
  306.                    $config{"last_gid"});
  307.  
  308.         if ($new_gid == -1) {
  309.         print STDERR "$0: ";
  310.         printf STDERR gtx("No GID is available in the range %d-%d (FIRST_GID - LAST_GID).\n"),$config{"first_gid"},$config{"last_gid"};
  311.             dief (gtx("The group `%s' was not created.\n"),$new_name);
  312.         }
  313.     }
  314.  
  315.     printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
  316.     &invalidate_nscd("group");
  317.     my $groupadd = &which('groupadd');
  318.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  319.     &invalidate_nscd("group");
  320.     print (gtx("Done.\n")) if $verbose;
  321.     exit 0;
  322. }
  323.  
  324.  
  325. ####################
  326. ## addusertogroup ##
  327. ####################
  328. if ($action eq "addusertogroup") {
  329.     dief (gtx("The user `%s' does not exist.\n"),$existing_user)
  330.     if (!defined getpwnam($existing_user));
  331.     dief (gtx("The group `%s' does not exist.\n"),$existing_group)
  332.     if (!defined getgrnam($existing_group));
  333.     if (&user_is_member($existing_user, $existing_group)) {
  334.     printf gtx("The user `%s' is already a member of `%s'.\n"),
  335.                 $existing_user,$existing_group if $verbose;
  336.     exit 0;            # not really an error
  337.     }
  338.  
  339.     printf gtx("Adding user `%s' to group `%s' ...\n"),$existing_user,$existing_group
  340.     if $verbose;
  341.     &invalidate_nscd();
  342.     my $gpasswd = &which('gpasswd');
  343.     &systemcall($gpasswd, '-a',$existing_user,$existing_group);
  344.     &invalidate_nscd();
  345.     print (gtx("Done.\n")) if $verbose;
  346.     exit 0;
  347. }
  348.  
  349.  
  350. ################
  351. ## addsysuser ##
  352. ################
  353. if ($action eq "addsysuser") {
  354.     if (existing_user_ok($new_name, $new_uid) == 1) {
  355.  
  356.         # a user with this name already exists; it's a problem when it's not a system user
  357.         my $tmp_u = getpwnam($new_name);
  358.         if (($tmp_u >= $config{"first_system_uid"}) and ($tmp_u <= $config{"last_system_uid"})) {
  359.         printf (gtx("The system user `%s' already exists. Exiting.\n"), $new_name) if $verbose;
  360.             exit 0;
  361.         }
  362.     printf (gtx("The user `%s' already exists. Exiting.\n"), $new_name) if $verbose;
  363.     exit 1;
  364.     }
  365.     if (existing_user_ok($new_name, $new_uid) == 2) {
  366.     printf (gtx("The user `%s' already exists with a different UID. Exiting.\n"), $new_name) if $verbose;
  367.     exit 1;
  368.     }
  369.  
  370.     if (!$ingroup_name && !defined($new_gid) && !$make_group_also) {
  371.       $new_gid = $nogroup_id;
  372.     }
  373.     check_user_group(1);
  374.  
  375.     if (!defined($new_uid) && $make_group_also) {
  376.     $new_uid = &first_avail_uid($config{"first_system_uid"},
  377.                    $config{"last_system_uid"});
  378.         if ($new_uid == -1) {
  379.         print STDERR "$0: ";
  380.         printf STDERR gtx("No UID/GID pair is available in the range %d-%d (FIRST_SYS_UID - LAST_SYS_UID).\n"),$config{"first_system_uid"},$config{"last_system_uid"};
  381.             dief (gtx("The user `%s' was not created.\n"),$new_name);
  382.         }
  383.         $new_gid = &first_avail_gid($config{"first_system_gid"},
  384.                                 $config{"last_system_gid"});
  385.     $ingroup_name = $new_name;
  386.     }
  387.     elsif (!defined($new_uid) && !$make_group_also) {
  388.     $new_uid = &first_avail_uid($config{"first_system_uid"},
  389.                    $config{"last_system_uid"});
  390.         if ($new_uid == -1) {
  391.         print STDERR "$0: ";
  392.         printf STDERR gtx("No UID is available in the range %d-%d (FIRST_SYS_UID - LAST_SYS_UID).\n"),$config{"first_system_uid"},$config{"last_system_uid"};
  393.         dief (gtx("The user `%s' was not created.\n"),$new_name);
  394.         }
  395.         if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  396.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  397.     else { dief (gtx("Internal error")); }
  398.     }
  399.     else {
  400.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  401.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  402.     elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
  403.     else { dief (gtx("Internal error")); }
  404.     }
  405.     printf (gtx("Adding system user `%s' (UID %d) ...\n"),$new_name,$new_uid) if $verbose;
  406.  
  407.     &invalidate_nscd();
  408.     # if we reach this point, and the group does already exist, we can use it.
  409.     if ($make_group_also && !getgrnam($new_name)) {
  410.     printf (gtx("Adding new group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
  411.     $undogroup = $new_name;
  412.        my $groupadd = &which('groupadd');
  413.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  414.     &invalidate_nscd("group");
  415.     }
  416.  
  417.     printf gtx("Adding new user `%s' (UID %d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name
  418.     if $verbose;
  419.     $home_dir = $special_home || &homedir($new_name, $ingroup_name);
  420.     $shell = $special_shell || '/bin/false';
  421.     $undouser = $new_name;
  422.     my $useradd = &which('useradd');
  423.     &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s',
  424.         $shell, '-u', $new_uid, $new_name);
  425.     if(!$disabled_login) {
  426.         my $usermod = &which('usermod');
  427.         &systemcall($usermod, '-p', '*', $new_name);
  428.     }
  429.     my $chage = &which('chage');
  430.     print "$chage -M 99999 $new_name\n" if ($verbose > 1);
  431.     # do _not_ use systemcall() here, since systemcall() dies on
  432.     # non-zero exit code and we need to do special handling here!
  433.     if (system($chage, '-M', '99999', $new_name)) {
  434.     if( ($?>>8) ne 15 ) {
  435.         &cleanup(sprintf((gtx("`%s' returned error code %d. Exiting.\n")), "$chage -M 99999 $new_name", $?>>8))
  436.           if ($?>>8);
  437.         &cleanup(sprintf((gtx("`%s' exited from signal %d. Exiting.\n")), "$chage -M 99999 $new_name", $?&255));
  438.     } else {
  439.         printf (gtx("%s failed with return code 15, shadow not enabled, password aging cannot be set. Continuing.\n"), $chage);
  440.     }
  441.     }
  442.     &invalidate_nscd();
  443.  
  444.     if(defined($new_gecos)) {
  445.     &ch_gecos($new_gecos);
  446.     }
  447.     create_homedir (0);
  448.  
  449.     exit 0;
  450. }
  451.  
  452.  
  453. #############
  454. ## adduser ##
  455. #############
  456. if ($action eq "adduser") {
  457.     if (!$ingroup_name && !defined($new_gid)) {
  458.     if ($config{"usergroups"} =~  /yes/i) { $make_group_also = 1; }
  459.     else { $new_gid = $config{"users_gid"}; }
  460.     }
  461.     check_user_group(0);
  462.     $first_uid = $new_firstuid || $config{"first_uid"};
  463.     $last_uid = $new_lastuid || $config{"last_uid"};
  464.     printf (gtx("Adding user `%s' ...\n"),$new_name) if $verbose;
  465.  
  466.     if (!defined($new_uid) && $make_group_also) {
  467.     $new_uid = &first_avail_uid($first_uid,
  468.                    $last_uid);
  469.                 
  470.         if ($new_uid == -1) {
  471.         print STDERR "$0: ";
  472.             printf STDERR gtx("No UID/GID pair is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$first_uid,$last_uid;
  473.         dief (gtx("The user `%s' was not created.\n"),$new_name);
  474.         }
  475.     $new_gid = &first_avail_gid($config{"first_gid"}, 
  476.                                 $config{"last_gid"});
  477.     $ingroup_name = $new_name;
  478.     }
  479.     elsif (!defined($new_uid) && !$make_group_also) {
  480.     $new_uid = &first_avail_uid($first_uid,
  481.                    $last_uid);
  482.     if ($new_uid == -1) {
  483.         print STDERR "$0: ";
  484.         printf STDERR gtx("No UID is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$config{"first_uid"},$config{"last_uid"};
  485.             dief (gtx("The user `%s' was not created.\n"),$new_name);
  486.         }
  487.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  488.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  489.     else { dief (gtx("Internal error")); }
  490.     }
  491.     else {
  492.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  493.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  494.     elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
  495.     else { dief (gtx("Internal error")); }
  496.     }
  497.  
  498.     &invalidate_nscd();
  499.     if ($make_group_also) {
  500.     printf (gtx("Adding new group `%s' (%d) ...\n"),$new_name,$new_gid) if $verbose;
  501.     $undogroup = $new_name;
  502.         my $groupadd = &which('groupadd');
  503.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  504.     &invalidate_nscd();
  505.     }
  506.  
  507.     printf gtx("Adding new user `%s' (%d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name
  508.     if $verbose;
  509.     $home_dir = $special_home || &homedir($new_name, $ingroup_name);
  510.     $shell = $special_shell || $config{"dshell"};
  511.     $undouser = $new_name;
  512.     my $useradd = &which('useradd');
  513.     &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s',
  514.         $shell, '-u', $new_uid, $new_name);
  515.     &invalidate_nscd();
  516.  
  517.     create_homedir (1); # copy skeleton data
  518.  
  519.     # useradd without -p has left the account disabled (password string is '!')
  520.     my $yesexpr = langinfo(YESEXPR());
  521.     if ($ask_passwd) {
  522.     for (;;) {
  523.           my $passwd = &which('passwd');
  524.       # do _not_ use systemcall() here, since systemcall() dies on
  525.       # non-zero exit code and we need to do special handling here!
  526.           system($passwd, $new_name);
  527.       my $ok = $?>>8;
  528.       if ($ok != 0) {
  529.             my $answer;
  530.             # hm, error, should we break now?
  531.         print (gtx("Permission denied\n")) if ($ok == 1);
  532.         print (gtx("invalid combination of options\n")) if ($ok == 2);
  533.         print (gtx("unexpected failure, nothing done\n")) if ($ok == 3);
  534.         print (gtx("unexpected failure, passwd file missing\n")) if ($ok == 4);
  535.         print (gtx("passwd file busy, try again\n")) if ($ok == 5);
  536.         print (gtx("invalid argument to option\n")) if ($ok == 6);
  537.         
  538.         # Translators: [y/N] has to be replaced by values defined in your
  539.         # locale.  You can see by running "locale noexpr" which regular
  540.         # expression will be checked to find positive answer.
  541.         print (gtx("Try again? [y/N] "));
  542.         chop ($answer=<STDIN>);
  543.         last if ($answer !~ m/$yesexpr/o);
  544.       }
  545.       else {
  546.         last; ## passwd ok
  547.       }
  548.     }
  549.     } else {
  550.     if(!$disabled_login) {
  551.            my $usermod = &which('usermod');
  552.         &systemcall($usermod, '-p', '*', $new_name);
  553.     }
  554.     }
  555.  
  556.     if (defined($new_gecos)) {
  557.     &ch_gecos($new_gecos);
  558.     }
  559.     else {
  560.     my $noexpr = langinfo(NOEXPR());
  561.     for (;;) {
  562.            my $chfn = &which('chfn');
  563.         &systemcall($chfn, $new_name);
  564.         # Translators: [y/N] has to be replaced by values defined in your
  565.         # locale.  You can see by running "locale yesexpr" which regular
  566.         # expression will be checked to find positive answer.
  567.         print (gtx("Is the information correct? [Y/n] "));
  568.         chop (my $answer=<STDIN>);
  569.         last if ($answer !~ m/$noexpr/o);
  570.     }
  571.     }
  572.  
  573.     if ( ( $add_extra_groups || $config{"add_extra_groups"} ) && defined($config{"extra_groups"}) ) {
  574.         printf (gtx("Adding new user `%s' to extra groups ...\n"), $new_name);
  575.         foreach my $newgrp ( split ' ', $config{"extra_groups"} ) {
  576.             if (!defined getgrnam($newgrp)) {
  577.                 warnf (gtx("The group `%s' does not exist.\n"),$newgrp);
  578.                 next;
  579.             }
  580.             if (&user_is_member($new_name, $newgrp)) {
  581.                 printf gtx("The user `%s' is already a member of `%s'.\n"),
  582.                         $new_name,$newgrp if $verbose;
  583.                 next;
  584.  
  585.             }
  586.  
  587.             printf gtx("Adding user `%s' to group `%s' ...\n"),$new_name,$newgrp
  588.                 if $verbose;
  589.             &invalidate_nscd();
  590.             my $gpasswd = &which('gpasswd');
  591.             &systemcall($gpasswd, '-M',
  592.                         join(',', get_group_members($newgrp), $new_name),
  593.                         $newgrp);
  594.             &invalidate_nscd();
  595.         }
  596.     }
  597.  
  598.  
  599.     if ($config{"quotauser"}) {
  600.     printf (gtx("Setting quota for user `%s' to values of user `%s' ...\n"), $new_name, $config{quotauser});
  601.     my $edquota = &which('edquota');
  602.     &systemcall($edquota, '-p', $config{quotauser}, $new_name);
  603.     }
  604.  
  605.     &systemcall('/usr/local/sbin/adduser.local', $new_name, $new_uid,
  606.         $new_gid, $home_dir) if (-x "/usr/local/sbin/adduser.local");
  607.     
  608.     exit 0;
  609. }
  610.  
  611. #
  612. # we never go here
  613. #
  614.  
  615.  
  616. # calculate home directory
  617. sub homedir {
  618.     my $dir = $config{"dhome"};
  619.     $dir .= '/' . $_[1] if ($config{"grouphomes"} =~ /yes/i);
  620.     $dir .= '/' . substr($_[0],0,1) if ($config{"letterhomes"} =~ /yes/i);
  621.     $dir .= '/' . $_[0];
  622.     return $dir;
  623. }
  624.  
  625.  
  626. # create_homedir -- create the homedirectory
  627. # parameter 
  628. #   1: $copy_skeleton: 
  629. #     if 0  -> don't copy the skeleton data
  630. #     if 1  -> copy the files in /etc/skel to the newly created home directory
  631. # return values:
  632. #   none
  633. sub create_homedir {
  634.   my ($copy_skeleton) = @_;
  635.  
  636.   if ($no_create_home) {
  637.       printf gtx("Not creating home directory `%s'.\n"), $home_dir if $verbose;
  638.   }
  639.   elsif (-e $home_dir) {
  640.       printf gtx("The home directory `%s' already exists.  Not copying from `%s'.\n"),
  641.       $home_dir,$config{skel} if $verbose && !$no_create_home;
  642.       my @homedir_stat = stat($home_dir);
  643.       my $home_uid = $homedir_stat[4];
  644.       my $home_gid = $homedir_stat[5];
  645.       if (($home_uid != $new_uid) || ($home_gid != $new_gid)) {
  646.       warnf gtx("Warning: The home directory `%s' does not belong to the user you are currently creating.\n"), $home_dir;
  647.       }
  648.       undef @homedir_stat; undef $home_uid; undef $home_gid;
  649.   }
  650.   else {
  651.       printf gtx("Creating home directory `%s' ...\n"),$home_dir if $verbose;
  652.       $undohome = $home_dir;
  653.       &mktree($home_dir) || &cleanup(sprintf(gtx("Couldn't create home directory `%s': %s.\n"), $home_dir, $!));
  654.       chown($new_uid, $new_gid, $home_dir)
  655.       || &cleanup("chown $new_uid:$new_gid $home_dir: $!\n");
  656.       $dir_mode = get_dir_mode($make_group_also);
  657.       chmod ($dir_mode, $home_dir) ||
  658.       &cleanup("chmod $dir_mode $home_dir: $!\n");
  659.  
  660.       if ($config{"skel"} && $copy_skeleton) {
  661.       printf gtx("Copying files from `%s' ...\n"),$config{skel} if $verbose;
  662.       open(FIND, "cd $config{skel}; find .  -print |")
  663.           || &cleanup(sprintf(gtx("fork for `find' failed: %s\n"), $!));
  664.       while (<FIND>) {
  665.           chop;
  666.           next if ($_ eq ".");
  667.           next if ($_ =~ qr/$config{skel_ignore_regex}/ );
  668.           ©_to_dir($config{"skel"}, $_, $home_dir, $new_uid,
  669.                 $new_gid, ($config{"setgid_home"} =~ /yes/i));
  670.       }
  671.       }
  672.   }
  673. }
  674.  
  675. # mktree: create a directory and all parent directories, we don't care about the rights and so on
  676. # parameters:
  677. #   tree: the path 
  678. # return values:
  679. #   none
  680. sub mktree {
  681.     my($tree) = @_;
  682.     my($done, @path);
  683.     my $default_dir_mode = 0755;
  684.  
  685.     $tree =~ s:^/*(.*)/*$:$1:; # chop off leading & trailing slashes
  686.     @path = split(/\//, $tree);
  687.  
  688.     $done = "";
  689.     while (@path) {
  690.     $done .= '/' . shift(@path);
  691.     -d $done || mkdir($done, $default_dir_mode) || return 0;
  692.     }
  693.     return 1;
  694. }
  695.  
  696. # existing_user_ok: check if there's already a user present on the system which satisfies the requirements
  697. # parameter:
  698. #   new_name: the name of the user to check
  699. #   new_uid : the UID of the user
  700. # return values:
  701. #   0 if the the user doesn't exist 
  702. #   1 if the user already exists with the specified uid (or $new_uid wasn't specified)
  703. #   2 if the user already exists, but $new_uid doesn't matches its uid 
  704. sub existing_user_ok {
  705.     my($new_name,$new_uid) = @_;
  706.     my ($dummy1,$dummy2,$uid);
  707.     if (($dummy1,$dummy2,$uid) = getpwnam($new_name)) {
  708.     if( defined($new_uid) && $uid == $new_uid ) {
  709.         return 1;
  710.     }
  711.     if (! defined($new_uid)) { 
  712.         return 1;
  713.     }
  714.         # TODO: do we really need this code? Range check shouldn't performed here
  715.     if( $uid >= $config{"first_system_uid"} &&
  716.         $uid <= $config{"last_system_uid" } ) {
  717.         return 2;
  718.     }
  719.     } else {
  720.     return 0;
  721.     }
  722. }
  723.  
  724. # existing_group_ok: check if there's already a group which satiesfies the requirements
  725. # parameter:
  726. #   new_name: the name of the group
  727. #   new_gid : the UID of the group
  728. # return values:
  729. #   0 if the group doesn't exist
  730. #   1 if the group already exists with the specified gid (or $new_gid wasn't specified)
  731. #   2 if the group already exists, but $new_gid doesn't match its gid 
  732. #   3 if the group already exists inside the system range
  733. sub existing_group_ok {
  734.     my($new_name,$new_gid) = @_;
  735.     my ($dummy1,$dummy2,$gid);
  736.     if (($dummy1,$dummy2,$gid) = getgrnam($new_name)) {
  737.  
  738.         # TODO: is this check required? There shouldn't be any gid outside of our allowed range anyways ...
  739.     if( $gid >= $config{"first_system_gid"} &&
  740.         $gid <= $config{"last_system_gid" } ) {
  741.         return 3;
  742.     }
  743.     if (! defined($new_gid)) {
  744.         return 1;
  745.     }
  746.         if ($gid == $new_gid) {
  747.             return 1;
  748.     } else {
  749.             return 2;
  750.         }
  751.     } else {
  752.     return 0;
  753.     }
  754. }
  755.  
  756.  
  757.  
  758. # check_user_group: ???
  759. # parameters:
  760. #   system: 0 if the user isn't a system user, 1 otherwise
  761. # return values:
  762. #   
  763. sub check_user_group {
  764.     my ($system) = @_;
  765.     if( !$system || !existing_user_ok($new_name, $new_uid) ) {
  766.     if( defined getpwnam($new_name) ) {
  767.         if( $system ) {
  768.         dief (gtx("The user `%s' already exists, and is not a system user.\n"),$new_name);
  769.         } else {
  770.         dief (gtx("The user `%s' already exists.\n"),$new_name);
  771.         }
  772.     }
  773.     dief (gtx("The UID %d is already in use.\n"),$new_uid)
  774.       if (defined($new_uid) && getpwuid($new_uid));
  775.     }
  776.     if ($make_group_also) {
  777.     if( !$system || !existing_group_ok($new_name, $new_uid) ) {
  778.         dief (gtx("The group `%s' already exists.\n"),$new_name)
  779.           if (defined getgrnam($new_name));
  780.         dief (gtx("The GID %d is already in use.\n"),$new_uid)
  781.           if (defined($new_uid) && defined(getgrgid($new_uid)));
  782.     }
  783.     }
  784.     else {
  785.     dief (gtx("The group `%s' does not exist.\n"),$ingroup_name)
  786.         if ($ingroup_name && !defined(getgrnam($ingroup_name)));
  787.     dief (gtx("The GID %d does not exist.\n"),$new_gid)
  788.         if (defined($new_gid) && !defined(getgrgid($new_gid)));
  789.     }
  790. }
  791.  
  792.  
  793. # copy_to_dir :
  794. # parameters:
  795. #   fromdir
  796. #   file
  797. #   todir
  798. #   newi
  799. #   newg
  800. #   sgiddir
  801. # return values:
  802. #   none
  803. sub copy_to_dir {
  804.     my($fromdir, $file, $todir, $newu, $newg, $sgiddir) = @_;
  805.  
  806.     if (-l "$fromdir/$file") {
  807.     my $target=readlink("$fromdir/$file") or &cleanup("readlink: $!\n");
  808.     my $curgid="$)";
  809.     my $curuid="$>";
  810.     my $error="";
  811.     $)="$newg";
  812.     $>="$newu";
  813.     symlink("$target", "$todir/$file") or $error="$!";
  814.         $>="$curuid";
  815.         $)="$curgid";
  816.     if( "$error" ne "" ) {
  817.         &cleanup("symlink: $!\n");
  818.     }
  819.     return;
  820.     }
  821.     elsif (-f "$fromdir/$file") {
  822.     open (FILE, "$fromdir/$file") || &cleanup("open $fromdir/$file: $!");
  823.     open (NEWFILE, ">$todir/$file") || &cleanup("open >$todir/$file: $!");
  824.  
  825.     (print NEWFILE <FILE>) || &cleanup("print $todir/$file: $!");
  826.     close FILE;
  827.     close(NEWFILE)  || &cleanup("close $todir/$file ");
  828.  
  829.     }
  830.     elsif (-d "$fromdir/$file") {
  831.     mkdir("$todir/$file", 700) || &cleanup("mkdir: $!");
  832.     }
  833.     else {
  834.     &cleanup(sprintf((gtx("Cannot deal with %s.\nIt is not a dir, file, or symlink.\n")), "$fromdir/$file"));
  835.     }
  836.     
  837.     chown($newu, $newg, "$todir/$file")
  838.     || &cleanup("chown $newu:$newg $todir/$file: $!\n");
  839.     $perm = (stat("$fromdir/$file"))[2] & 07777;
  840.     $perm |= 02000 if (-d "$fromdir/$file" && ($perm & 010) && $sgiddir);
  841.     chmod($perm, "$todir/$file") || &cleanup("chmod $todir/$file: $!\n");
  842. }
  843.        
  844.  
  845. # checkname: perform some sanity checks
  846. # parameters:
  847. #   name: the name to check
  848. #   system: 0 if the user isn't a system user, 1 otherwise
  849. # return values:
  850. #   none (exits on error)
  851. sub checkname {
  852.     my ($name, $system) = @_;
  853.     if ($name !~ /^[_.A-Za-z0-9][-\@_.A-Za-z0-9]*\$?$/) {
  854.     printf STDERR
  855. (gtx("%s: To avoid problems, the username should consist only of
  856. letters, digits, underscores, periods, at signs and dashes, and not start with
  857. a dash (as defined by IEEE Std 1003.1-2001). For compatibility with Samba
  858. machine accounts \$ is also supported at the end of the username\n"), $0);
  859.         exit 1;
  860.     }
  861.     if ($system
  862.         ? $name !~ qr/$config{"name_regex_system"}/
  863.         : $name !~ qr/$config{"name_regex"}/) {
  864.       if ($allow_badname) {
  865.     print (gtx("Allowing use of questionable username.\n")) if ($verbose);
  866.       }
  867.       else {
  868.         printf STDERR
  869. (gtx("%s: Please enter a username matching the regular expression configured
  870. via the NAME_REGEX[_SYSTEM] configuration variable.  Use the `--force-badname'
  871. option to relax this check or reconfigure NAME_REGEX or NAME_REGEX_SYSTEM.\n"), $0);
  872.         exit 1;
  873.       }
  874.     }
  875. }
  876.  
  877. # first_avail_uid: return the first available uid in given range
  878. # parameters:
  879. #   min, max: the range
  880. # return values:
  881. #   -1 if no free uid is available
  882. #  otherwise the choosen uid
  883. sub first_avail_uid {
  884.     my ($min, $max) = @_;
  885.     printf (gtx("Selecting UID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
  886.  
  887.     my $t = $min;
  888.     while ($t <= $max) {
  889.        return $t if (!defined(getpwuid($t)));
  890.        $t++;
  891.     }
  892.     return -1; # nothing available
  893. }
  894.  
  895. # first_avail_gid: return the first available gid in given range
  896. # parameters:
  897. #   min, max: the range
  898. # return values:
  899. #   -1 if no free gid is available
  900. #   otherwise the choosen gid
  901. sub first_avail_gid {
  902.     my ($min, $max) = @_;
  903.     printf (gtx("Selecting GID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
  904.  
  905.     my $t = $min;
  906.     while ($t <= $max) {
  907.        return $t if (!defined(getgrgid($t)));
  908.        $t++;
  909.     }
  910.     return -1; # nothing available
  911. }
  912.  
  913. sub ch_gecos {
  914.     my $chfn = &which('chfn');
  915.     my $gecos = shift;
  916.     if($gecos =~ /,/)
  917.       {
  918.       my($gecos_name,$gecos_room,$gecos_work,$gecos_home,$gecos_other)
  919.         = split(/,/,$gecos);
  920.  
  921.       &systemcall($chfn, '-f', $gecos_name, '-r', $gecos_room, $new_name);
  922.       &systemcall($chfn,'-w',$gecos_work,$new_name)
  923.         if(defined($gecos_work));
  924.       &systemcall($chfn,'-h',$gecos_home,$new_name)
  925.         if(defined($gecos_home));
  926.       &systemcall($chfn,'-o',$gecos_other,$new_name)
  927.         if(defined($gecos_other));
  928.       }
  929.     else
  930.       {
  931.       &systemcall($chfn, '-f', $gecos, $new_name);
  932.       }
  933. }
  934.  
  935. # user is member of group?
  936. sub user_is_member {
  937.     my($user, $group) = @_;
  938.     for (split(/ /, (getgrnam($group))[3])) {
  939.     return 1 if ($user eq $_);
  940.     }
  941.     return 0;
  942. }
  943.  
  944.  
  945. sub cleanup {
  946.     my ($msg) = @_;
  947.     printf (gtx("Stopped: %s\n"),$msg);
  948.     if ($undohome) {
  949.     printf (gtx("Removing directory `%s' ...\n"),$undohome);
  950.     &systemcall('rm', '-rf', $undohome);
  951.     }
  952.     if ($undouser) {
  953.     printf (gtx("Removing user `%s' ...\n"),$undouser);
  954.     &systemcall('userdel', $undouser);
  955.     }
  956.     if ($undogroup) {
  957.     printf (gtx("Removing group `%s' ...\n"),$undogroup);
  958.     &systemcall('groupdel', $undogroup);
  959.     }
  960.     # do we need to invalidate the nscd cache here, too?
  961.     exit 1;
  962. }
  963.  
  964. sub handler {
  965.     my($sig) = @_;
  966.     # Translators: the variable %s is INT, QUIT, or HUP.
  967.     # Please do not insert a space character between SIG and %s.
  968.     &cleanup(sprintf(gtx("Caught a SIG%s.\n"), $sig));
  969. }
  970.     
  971.  
  972. sub version {
  973.     printf (gtx("adduser version %s\n\n"), $version);
  974.     print gtx("Adds a user or group to the system.
  975.   
  976. Copyright (C) 1997, 1998, 1999 Guy Maor <maor\@debian.org>
  977. Copyright (C) 1995 Ian Murdock <imurdock\@gnu.ai.mit.edu>,
  978.                    Ted Hajek <tedhajek\@boombox.micro.umn.edu>
  979. \n");
  980.     print gtx(
  981. "This program is free software; you can redistribute it and/or modify
  982. it under the terms of the GNU General Public License as published by
  983. the Free Software Foundation; either version 2 of the License, or (at
  984. your option) any later version.
  985.  
  986. This program is distributed in the hope that it will be useful, but
  987. WITHOUT ANY WARRANTY; without even the implied warranty of
  988. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  989. General Public License, /usr/share/common-licenses/GPL, for more details.
  990. ");
  991. }
  992.  
  993. sub usage {
  994.     printf gtx(
  995. "adduser [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID]
  996. [--firstuid ID] [--lastuid ID] [--gecos GECOS] [--ingroup GROUP | --gid ID]
  997. [--disabled-password] [--disabled-login] USER
  998.    Add a normal user
  999.  
  1000. adduser --system [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID]
  1001. [--gecos GECOS] [--group | --ingroup GROUP | --gid ID] [--disabled-password]
  1002. [--disabled-login] USER
  1003.    Add a system user
  1004.  
  1005. adduser --group [--gid ID] GROUP
  1006. addgroup [--gid ID] GROUP
  1007.    Add a user group
  1008.  
  1009. addgroup --system [--gid ID] GROUP
  1010.    Add a system group
  1011.  
  1012. adduser USER GROUP
  1013.    Add an existing user to an existing group
  1014.  
  1015. general options:
  1016.   --quiet | -q      don't give process information to stdout
  1017.   --force-badname   allow usernames which do not match the
  1018.                     NAME_REGEX[_SYSTEM] configuration variable
  1019.   --help | -h       usage message
  1020.   --version | -v    version number and copyright
  1021.   --conf | -c FILE  use FILE as configuration file\n\n");
  1022. }
  1023.  
  1024. sub get_dir_mode
  1025.   {
  1026.       my $setgid = shift;
  1027.       # no longer make home directories setgid per default (closes: #64806)
  1028.       $setgid = 0 unless $config{"setgid_home"} =~  /yes/i;
  1029.  
  1030.       my $dir_mode = $config{"dir_mode"};
  1031.       if(!defined($dir_mode) || ! ($dir_mode =~ /[0-7]{3}/ ||
  1032.                    $dir_mode =~ /[0-7]{4}/))
  1033.     {
  1034.         $dir_mode = $setgid ? 2755 : 0755;
  1035.     }
  1036.       else
  1037.     {
  1038.         $dir_mode = $config{"dir_mode"};
  1039.         if($setgid && (length($dir_mode) == 3 || $dir_mode =~ /^[0-1|4-5][0-7]{3}$/))
  1040.           {
  1041.           $dir_mode += 2000;
  1042.           }
  1043.     }
  1044.       return oct($dir_mode);
  1045.   }
  1046.  
  1047. # Local Variables:
  1048. # mode:cperl
  1049. # cperl-indent-level:4
  1050. # End:
  1051.  
  1052. # vim:set ai et sts=4 sw=4 tw=0:
  1053.